//-----------------------------------------------------------------------
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "devsetup.h"
#include "plotter.h"
#include "about.h"
#include "widegraph.h"

#define NFFT 32768

WideGraph* g_pWideGraph = NULL;

QString rev="$Rev: 6 $";
QString Program_Title_Version="  WSPR v3.9, r" + rev.mid(6,3) +
                              "    by K1JT";
const double Duration      = 5.0;
const double ToneFrequency = 600;
extern const int DataFrequency = 48000;
qint16* wave;

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  QActionGroup *paletteGroup;
  paletteGroup = new QActionGroup(this);
  ui->actionCuteSDR->setActionGroup(paletteGroup);
  ui->actionLinrad->setActionGroup(paletteGroup);
  m_canvas=ui->audioMeter;

  setWindowTitle(Program_Title_Version);
  qRegisterMetaType< std::valarray<qint16> >("std::valarray<qint16>");

  ui->framePlot->setWide(false);
  ui->framePlot->setBinsPerPixel(1);

//--------------------------------------------------------------------------
// connect signals
//--------------------------------------------------------------------------
  connect(&soundInThread, SIGNAL(readyForFFT(int,int)),
             this, SLOT(dataSink(int, int)));
  connect(&soundInThread, SIGNAL(error(QString)), this,
          SLOT(showSoundInError(QString)));
  connect(&soundInThread, SIGNAL(status(QString)), this,
          SLOT(showStatusMessage(QString)));
  createStatusBar();

  m_waterfallAvg = 1;
  m_network = false;
  m_go = false;

//  fp=fopen("test.dat","w");

  readSettings();		              // restore user's persistent settings

//--------------------------------------------------------------------------
// Generate test data for SoundOut (temporary!)
//--------------------------------------------------------------------------

  qint64 npts = DataFrequency * Duration;
  wave=(qint16*)malloc(2*npts);

  qreal pha=0.;
  qreal dpha=2.0*M_PI*ToneFrequency/DataFrequency;
  qreal ddpha=dpha/npts;

  for (int i=0; i<npts; i++) {
    qint16 value = static_cast<qint16>(32767.0*qSin(pha));
    wave[i]=value;
    pha += dpha;
    dpha += ddpha;
  }

  soundInThread.setRate(double(DataFrequency));
  soundOutThread.setRate(double(DataFrequency));

  Qt::WindowFlags flags = Qt::Dialog | Qt::WindowCloseButtonHint;

  g_pWideGraph = new WideGraph(this);
  g_pWideGraph->setWindowTitle("Wide Graph");
  g_pWideGraph->setGeometry(m_wideGraphGeom);
  g_pWideGraph->show();
  on_monitorButton_clicked();                 // autostart
  decodeThread.start();
}

MainWindow::~MainWindow()
{
  if (soundInThread.isRunning()) {
    soundInThread.quit();
    soundInThread.wait(1000);
    decodeThread.quit();
    decodeThread.wait(1000);
  }
  writeSettings();
  delete ui;
}

//--------------------------------------------------------------------------
// Save the user configuration
//--------------------------------------------------------------------------
void MainWindow::writeSettings()
{
  QString inifile(QApplication::applicationDirPath());
  inifile += "/map65.ini";
  QSettings settings(inifile, QSettings::IniFormat);
  settings.beginGroup("MainWindow");
  settings.setValue("geometry", saveGeometry());
  if(g_pWideGraph->isVisible()) {
    m_wideGraphGeom = g_pWideGraph->geometry();
    settings.setValue("WideGraphGeom",m_wideGraphGeom);
  }
  settings.endGroup();

  settings.beginGroup("Common");
  settings.setValue("SoundInIndex",m_SoundInIndex);
  settings.setValue("SoundOutIndex",m_SoundOutIndex);
  settings.setValue("PlotZero",ui->framePlot->getPlotZero());
  settings.setValue("PlotGain",ui->framePlot->getPlotGain());
  settings.setValue("WaterfallAvg",m_waterfallAvg);
  settings.setValue("NetworkInput", m_network);
  settings.setValue("PaletteCuteSDR",ui->actionCuteSDR->isChecked());
  settings.setValue("PaletteLinrad",ui->actionLinrad->isChecked());
  settings.endGroup();
}

//--------------------------------------------------------------------------
// Restore the user configuration
//--------------------------------------------------------------------------
void MainWindow::readSettings()
{
  QString inifile(QApplication::applicationDirPath());
  inifile += "/map65.ini";
  QSettings settings(inifile, QSettings::IniFormat);
  settings.beginGroup("MainWindow");
  restoreGeometry(settings.value("geometry").toByteArray());
  m_wideGraphGeom = settings.value("WideGraphGeom", \
                                   QRect(9,9,706,264)).toRect();
  settings.endGroup();

  settings.beginGroup("Common");
  m_SoundInIndex = settings.value("SoundInIndex", 0).toInt();
  m_SoundOutIndex = settings.value("SoundOutIndex", 0).toInt();
  m_network = settings.value("NetworkInput",0).toBool();
  ui->framePlot->setPlotZero(settings.value("PlotZero", 0).toInt());
  ui->framePlot->setPlotGain(settings.value("PlotGain", 0).toInt());
  m_waterfallAvg = settings.value("WaterfallAvg", 0).toInt();
  ui->zeroSpinBox->setValue(ui->framePlot->getPlotZero());
  ui->gainSpinBox->setValue(ui->framePlot->getPlotGain());
  ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
  ui->actionCuteSDR->setChecked(settings.value(
                                  "PaletteCuteSDR",0).toBool());
  if (ui->actionCuteSDR->isChecked())
    on_actionCuteSDR_triggered();

  ui->actionLinrad->setChecked(settings.value(
                                 "PaletteLinrad",0).toBool());
  if (ui->actionLinrad->isChecked())
    on_actionLinrad_triggered();
  settings.endGroup();

  if (!ui->actionLinrad->isChecked() && !ui->actionCuteSDR->isChecked()) {
    on_actionLinrad_triggered();
    ui->actionLinrad->setChecked(true);
  }
}

//--------------------------------------------------------------------------
// Public slots
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------
// dataSink -- called when enough data are available for the next
// half-symbol  FFT
//--------------------------------------------------------------------------
void MainWindow::dataSink(int kb, int k)         // dataSink
{
  static float s[NFFT],savg[NFFT];
  static int n=0;
  int nsec;
  static int nsec0=-999;
  int i0,nkhz;
  float px=0.0,py=0.0;

  //Get x,y power, polarized spectrum, and nkhz
  symspec_(&kb, &k, &px, &py, s, &nkhz);
  m_canvas->setLevel(px,py);          //Update the bargraph
  g_pWideGraph->dataSink2(s, nkhz);

  //Average spectra over specified number
  if (n==0) {
    for (int i=0; i<NFFT; i++)
      savg[i]=s[i];
  } else {
    for (int i=0; i<NFFT; i++)
      savg[i] += s[i];
  }
  n++;

  if(gcom0_.qsoFreq<=0) gcom0_.qsoFreq=125;
  lab1->setText("QSO freq: " + QString::number(gcom0_.qsoFreq));
  if (n>=m_waterfallAvg) {
    //Normalize the average
    for (int i=0; i<NFFT; i++)
        savg[i] /= n;

//Update the main-window spectral display
// ### Why the "-1.0" in what follows??? ###
    i0 = (gcom0_.qsoFreq-125+48+1.27046-1.0)*NFFT/96.0 + 0.5;  //start index
    ui->framePlot->draw(&savg[i0]);
    n=0;
//    lab2->setText(QString::number(i0));
  }

  qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
  nsec = ms/1000;             // Time according to this computer
  nsec0=nsec;

}

void MainWindow::showSoundInError(const QString& errorMsg)
{
  QMessageBox::critical(this, tr("Error in SoundIn"), errorMsg);
}

void MainWindow::showStatusMessage(const QString& statusMsg)
{
  statusBar()->showMessage(statusMsg);
}

//--------------------------------------------------------------------------
// Private slots
//--------------------------------------------------------------------------
// on_actionDeviceSetup_triggered
//--------------------------------------------------------------------------
void MainWindow::on_actionDeviceSetup_triggered()
{
  DevSetup dlg(this);
  dlg.SetInputIndex(m_SoundInIndex);
  dlg.SetOutputIndex(m_SoundOutIndex);
  dlg.setNetwork(m_network);
  if(QDialog::Accepted == dlg.exec() )
  {
    soundInThread.quit();
    m_go = false;
    /*
    if(CSdrInterface::RUNNING == m_Status)
    {
      m_pSdrInterface->StopSdr();
      ui->framePlot->SetRunningState(false);
    }
    */
    m_SoundInIndex = dlg.GetInputIndex();
    m_SoundOutIndex = dlg.GetOutputIndex();
    m_network = dlg.isNetwork();
  }
}

//--------------------------------------------------------------------------
// on_monitorButton_clicked
//--------------------------------------------------------------------------
void MainWindow::on_monitorButton_clicked()
{
  if (!m_go) {
    QAudioDeviceInfo  DeviceInfo;
    QList<QAudioDeviceInfo> m_InDevices;
    QAudioDeviceInfo  m_InDeviceInfo;
    m_InDevices = DeviceInfo.availableDevices(QAudio::AudioInput);
    m_InDeviceInfo = m_InDevices.at(m_SoundInIndex);

    soundInThread.setInputDevice(m_InDeviceInfo);
    soundInThread.setRate(DataFrequency);
//    soundInThread.setBufSize(4096);
    soundInThread.setBufSize(262144);
    soundInThread.setNetwork(m_network);
    soundInThread.start(QThread::HighestPriority);
    m_go = true;
  } else {
    soundInThread.quit();
    m_go = false;
  }
}

//--------------------------------------------------------------------------
// on_waterfallAvg_valueChanged
//--------------------------------------------------------------------------
void MainWindow::on_waterfallAvgSpinBox_valueChanged(int n)
{
  m_waterfallAvg = n;
}

//--------------------------------------------------------------------------
// on_actionExit_triggered
//--------------------------------------------------------------------------
void MainWindow::on_actionExit_triggered()
{
  qApp->exit(0);
}

//--------------------------------------------------------------------------
// on_actionAbout_trigerred
//--------------------------------------------------------------------------
void MainWindow::on_actionAbout_triggered()
{
  CAboutDlg dlg(this,Program_Title_Version);
  dlg.exec();
}

//--------------------------------------------------------------------------
// OnExit
//--------------------------------------------------------------------------
void MainWindow::OnExit()
{
  qApp->exit(0);
}

//--------------------------------------------------------------------------
// on_actionLinrad_triggered
//--------------------------------------------------------------------------
void MainWindow::on_actionLinrad_triggered()
{
#include "palette_linrad.h"
}

//--------------------------------------------------------------------------
// on_actionCuteSDR_triggered
//--------------------------------------------------------------------------
void MainWindow::on_actionCuteSDR_triggered()
{
//  ui->framePlot->ui->framePlot->m_ColorTbl
  for( int i=0; i<256; i++) {
    if( (i<43) )
      ui->framePlot->m_ColorTbl[i].setRgb( 0,0, 255*(i)/43);
    if( (i>=43) && (i<87) )
      ui->framePlot->m_ColorTbl[i].setRgb( 0, 255*(i-43)/43, 255 );
    if( (i>=87) && (i<120) )
      ui->framePlot->m_ColorTbl[i].setRgb( 0,255, 255-(255*(i-87)/32));
    if( (i>=120) && (i<154) )
      ui->framePlot->m_ColorTbl[i].setRgb( (255*(i-120)/33), 255, 0);
    if( (i>=154) && (i<217) )
      ui->framePlot->m_ColorTbl[i].setRgb( 255, 255 - (255*(i-154)/62), 0);
    if( (i>=217)  )
      ui->framePlot->m_ColorTbl[i].setRgb( 255, 0, 128*(i-217)/38);
  }
}

//--------------------------------------------------------------------------
// on_playButton_clicked()
//--------------------------------------------------------------------------
void MainWindow::on_playButton_clicked()
{
  QAudioDeviceInfo  DeviceInfo;
  QList<QAudioDeviceInfo> outDevices;
  outDevices = DeviceInfo.availableDevices(QAudio::AudioOutput);
  QAudioDeviceInfo  outDeviceInfo;
  outDeviceInfo = outDevices.at(m_SoundOutIndex);
  soundOutThread.setOutputDevice(outDeviceInfo);
  soundOutThread.setRate(DataFrequency);
  soundOutThread.start();
  qint64 npts = DataFrequency * Duration;
  soundOutThread.play(wave,npts);

}

//--------------------------------------------------------------------------
// on_txMuteButton_clicked()
//--------------------------------------------------------------------------
void MainWindow::on_txMuteButton_clicked()
{
  soundOutThread.txMute();
}

//--------------------------------------------------------------------------
// on_abortButton_clicked
//--------------------------------------------------------------------------
void MainWindow::on_abortButton_clicked()
{
  soundOutThread.abort();
}

void MainWindow::on_zeroSpinBox_valueChanged(int value)
{
  ui->framePlot->setPlotZero(value);
}

void MainWindow::on_gainSpinBox_valueChanged(int value)
{
  ui->framePlot->setPlotGain(value);
}

void MainWindow::keyPressEvent( QKeyEvent *e )
{
  switch(e->key())
  {
  case Qt::Key_F11:
    if(e->modifiers() & Qt::ShiftModifier) {
//      qDebug() << "Shift+F11";
    } else {
//      qDebug() << "F11";
    }
    break;
  case Qt::Key_F12:
    if(e->modifiers() & Qt::ShiftModifier) {
//      qDebug() << "Shift+F12";
    } else {
//      qDebug() << "F12";
    }
    break;
  }
}

bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
//  if (object == form && event->type() == QEvent::KeyPress)
  if (event->type() == QEvent::KeyPress)
     {
         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

//Use the event in parent using its keyPressEvent()
         MainWindow::keyPressEvent(keyEvent);

         return QObject::eventFilter(object, event);
     }

     return QObject::eventFilter(object, event);
}

void MainWindow::createStatusBar()
{
//  statusBar()->showMessage("Ready");
  lab1 = new QLabel(" QSO freq: 125 ");
  lab1->setAlignment(Qt::AlignHCenter);
  lab1->setMinimumSize(lab1->sizeHint());
  lab1->setFrameStyle(QFrame::Panel | QFrame::Sunken);
  statusBar()->addWidget(lab1);
//  connect
}

void MainWindow::updateStatusBar()
{

}
